#pragma once

#include<iostream>
#include<string>
#include<string.h>
#include<cstdio>
#include<cerrno>
#include<memory>
#include<strings.h>

#include<sys/types.h>
#include<sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include"Log.hpp"
#include"Common.hpp"
#include "InetAddr.hpp"


using namespace LogModule;

const static int gsockfd = -1;
//const static std::string gdefaultip = "127.0.0.1";//本地主机
const static uint16_t gdefaultport = 8080;

class UdpServer
{
public:
    UdpServer(uint16_t port = gdefaultport)
    :_addr(port)
    ,_sockfd(gsockfd)
    ,_isrunning(false)
    {}


    void InitServer()
    {
        //1.创建套接字
        _sockfd = ::socket(AF_INET,SOCK_DGRAM,0);//本地，数据报通信的套接字
        if(_sockfd < 0)
        {
            LOG(LogLevel::FATAL) <<"socket:"<<strerror(errno);
            Die(SOCKET_ERR);
        }
        LOG(LogLevel::INFO)<<"socket success,socketfd is : "<<_sockfd;

        //2.填充网络信息，并使用bind绑定
        //填充网络信息的时候，此时并没有把socket信息填入到内核中
        // struct  sockaddr_in local;
        // bzero(&local,sizeof(local));
        // local.sin_family = AF_INET;
        // local.sin_port = ::htons(_port);//主机转网络
        // local.sin_addr.s_addr = INADDR_ANY;//可以接受任意ip，只要端口号一样即可
        // //local.sin_addr.s_addr = ::inet_addr(_ip.c_str());

        //bind，嵌入到内核中
        int n = ::bind(_sockfd,_addr.NetAddr(),_addr.NetAddrLen());
        if(n  < 0)
        {
            LOG(LogLevel::FATAL) <<"bind :"<<strerror(errno);
            Die(BIND_ERR);
        }
        LOG(LogLevel::DEBUG)<<"bind success";

    }
    void Start()
    {
        _isrunning = true;
        //一般来说，服务器打开之后就会一直运转不会停止
        while(true)
        {
            char inbuffer[1024];
            struct sockaddr_in peer;//使用recvfrom必须设定
            socklen_t len = sizeof(peer);

            //阻塞式等待客户端发消息
            ssize_t n = recvfrom(_sockfd,inbuffer,sizeof(inbuffer),0,CONV(&peer),&len);
            if(n > 0)
            {
                //谁发给的我，发的内容是什么
                // uint16_t clientport = ::ntohs(peer.sin_port);
                // std::string clientip = ::inet_ntoa(peer.sin_addr);
                InetAddr cli(peer);
                inbuffer[n] = 0;
                
                std::string clientinfo = cli.Ip()+" : "+ std::to_string(cli.Port())+" # "+inbuffer;
                LOG(LogLevel::INFO) << clientinfo;

                //向客户端回显消息
                std::string echo_string = "echo # ";
                echo_string += inbuffer;

                ::sendto(_sockfd,echo_string.c_str(),sizeof(echo_string),0,CONV(&peer),sizeof(peer));
            }
        }

        _isrunning = false;
    }

    ~UdpServer()
    {
        if(_sockfd > gsockfd)
            ::close(_sockfd);
    }

private:
    int _sockfd;//文件描述符
    // //std::string _ip;//服务器的ip地址
    //uint16_t _port;//服务器的端口号
    InetAddr _addr;
    bool _isrunning;//运行状态

};
